package com.yeqing.crazymakercircle.bufferDemo;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

public class NioSendClient {

    private static final Charset charset = StandardCharsets.UTF_8;

    /**
     * 向服务器端传输文件
     */
    public static void sendFile(String srcPath, String destFile) {
        File file = new File(srcPath);
        if (!file.exists()) {
            System.out.println("文件不存在");
            return;
        }

        try (
                FileChannel fileChannel = new FileInputStream(file).getChannel();
                SocketChannel socketChannel = SocketChannel.open();
        ) {
            socketChannel.socket().connect(new InetSocketAddress("127.0.0.1", 18899));

            socketChannel.configureBlocking(false);
            System.out.println("Client 成功连接服务端");

            while (!socketChannel.finishConnect()) {
                // 不断的自旋、等待，或者做一些其他的事情
            }
            // 发送文件名称和长度
            ByteBuffer buffer = sengFileNameAndLength(destFile, file, socketChannel);
            // 发送文件内容
            int length = sendContent(file, fileChannel, socketChannel, buffer);
            if (length == -1) {
                socketChannel.shutdownOutput();
            }
            System.out.println("======== 文件传输成功 ========");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    // 方法：发送文件内容
    public static int sendContent(File file, FileChannel fileChannel,
                           SocketChannel socketChannel,
                           ByteBuffer buffer) throws IOException {
        // 发送文件内容
        System.out.println("开始传输文件");
        int length = 0;
        long progress = 0;
        while ((length = fileChannel.read(buffer)) > 0) {
            buffer.flip();
            socketChannel.write(buffer);
            buffer.clear();
            progress += length;
            System.out.println("| " + (100 * progress / file.length()) + " % |");
        }
        return length;
    }


    // 方法：发送文件名称和长度
    public static ByteBuffer sengFileNameAndLength(String destFile,
                                            File file,
                                            SocketChannel socketChannel) throws IOException {
        // 发送文件名称
        ByteBuffer fileNameByteBuffer = charset.encode(destFile);
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        // 发送文件名称长度
        int fileNameLen = fileNameByteBuffer.capacity();
        buffer.putInt(fileNameLen);
        buffer.flip();
        socketChannel.write(buffer);
        buffer.clear();
        System.out.println("Client 文件名称长度发送完成:" + fileNameLen);

        // 发送文件名称
        socketChannel.write(fileNameByteBuffer);
        System.out.println("Client 文件名称发送完成:" + destFile);

        // 发送文件长度
        buffer.putLong(file.length());
        buffer.flip();
        socketChannel.write(buffer);
        buffer.clear();
        System.out.println("Client 文件长度发送完成:" + file.length());

        return buffer;
    }

    public static void main(String[] args) {
        sendFile("/Users/cyq/Develop/三国/张飞.txt", "zf.txt");
    }
}